/*
 * Context.cpp
 *
 *  Created on: Apr 29, 2012
 *      Author: kobe
 */

#include "Context.h"

#include "Util.h"
#include <string>
#include <cstdlib>
#include <iostream>

Context::Context() {

}

Context::Context(std::string input) {
	this->mParent = NULL;
	this->mType = PROPOSITIONCONTEXT;
	bool isActionContext = true;
	if (isOnlyAnnotatedContext(input)) {
		size_t start, end;
		std::string first = getBracketContent(input, &start, &end);
		std::string type(first, 0, 2);
		//Test if the context is annotated by agent or action-context
		if (type.compare("an") == 0 || type.compare("aa") == 0
				|| type.compare("md") == 0 || type.compare("cj") == 0
				|| type.compare("dj") == 0 || type.compare("bd") == 0
				|| type.compare("sq") == 0) {
			Context* annotation;
			size_t s;
			while (first.size() > 0) {
				annotation = getContext(&first, &s);
				annotation->setParent(this);
				this->mActionList.push_back(annotation);
			}
			this->mType = ACTIONANNOTATEDCONTEXT;
		} else {
			Agent* agent = new Agent(first);
			this->mAgentList.push_back(agent);
		}
		std::string t(skipBracket(input));
		std::string second = getBracketContent(t, &start, &end);
		Context *context;
		size_t s;
		while (second.size() > 0) {
			//std::cout << "Content of second: " << second << std::endl;
			context = getContext(&second, &s);
			if (!context->isActionContext()) {
				isActionContext = false;
			}
			//std::cout << "Second context:" << context->toString() << std::endl;
			context->setParent(this);
			this->mItemList.push_back(context);
		}
	} else {
		size_t t;
		std::vector<Context*> list;
		while (input.size() > 0) {
			//std::cout << "Content of input: " << input << std::endl;
			Context* c = getContext(&input, &t);
//			std::cout << c->toString() << std::endl;
//			std::cout << c->isActionContext() << std::endl;
			if (!c->isActionContext()) {
				isActionContext = false;
			}
			c->setParent(this);
			list.push_back(c);
		}
		if (isActionContext) {
			this->mType = ACTIONCONTEXT;
		} else {
			this->mType = PROPOSITIONCONTEXT;
		}
		this->setItemList(list);
	}
}

std::vector<Context*> Context::getItemList() const {
	return mItemList;
}

Proposition *Context::getProposition() const {
	return mProposition;
}

ContextItem Context::getType() const {
	return mType;
}

void Context::setItemList(std::vector<Context*> itemList) {
	mItemList = itemList;
	for (size_t i = 0; i < mItemList.size(); i++) {
		mItemList[i]->setParent(this);
	}
}

void Context::setProposition(Proposition *proposition) {
	mProposition = proposition;
	if (mProposition != NULL && mProposition->isAction()) {
		mType = CONTEXT_ACTION;
	}
}

bool Context::isActionContext() {
	if (mType == ACTIONCONTEXT || mType == CONTEXT_ACTION) {
		return true;
	} else {
		return false;
	}
}

void Context::setType(ContextItem type) {
	mType = type;
}

std::vector<Agent*> Context::getAgentList() const {
	return mAgentList;
}

void Context::setAgentList(std::vector<Agent*> agentList) {
	mAgentList = agentList;
}

Context *Context::getParent() const {
	return mParent;
}

void Context::setParent(Context *parent) {
	mParent = parent;
}

std::vector<Context*> Context::getActionList() const {
	return mActionList;
}

void Context::setActionList(std::vector<Context*> actionList) {
	mActionList = actionList;
	for (size_t i = 0; i < mActionList.size(); i++) {
		mActionList.at(i)->setParent(this);
	}
}

bool Context::isOnlyAnnotatedContext(std::string input) {
	std::string duplicate(input);
	std::string type(input, 0, 2);
	if (type.compare("an") == 0) {
		std::string result = skipBracket(skipBracket(duplicate));
		if (result.size() == 0) {
			return true;
		} else {
			return false;
		}
	}
	return false;
}

Context::Context(Proposition* i) {
	this->mProposition = i;
	if (mProposition->isAction()) {
		this->mType = CONTEXT_ACTION;
	} else {
		this->mType = CONTEXT_PROPOSITION;
	}
	this->mParent = NULL;
}

std::string Context::toString() {
	std::string result;
	if (this->isAnnotated()) {
		result += "an{";
		//annotation
		if (this->mAgentList.size() > 0) {
			for (size_t i = 0; i < mAgentList.size(); i++) {
				result += mAgentList[i]->getName();
			}
		} else {
			for (size_t i = 0; i < mActionList.size(); i++) {
				result += mActionList[i]->toString();
			}
		}
		result += "}{";
	}
	//body
	switch (mType) {
	case CONTEXT_PROPOSITION:
	case CONTEXT_ACTION:
		result += mProposition->toString();
		break;
	case ACTIONCONTEXT:
	case ACTIONANNOTATEDCONTEXT:
	case PROPOSITIONCONTEXT:
		for (size_t i = 0; i < mItemList.size(); i++) {
			result += this->mItemList[i]->toString();
		}
		break;
	}
	if (this->isAnnotated()) {
		result += "}";
	}
	return result;
}

Context* Context::getContext(std::string* input, size_t* pos) {
	std::string duplicate(input->c_str());
	std::string type(input->c_str(), 0, 2);
	if (type.compare("an") == 0) {
		size_t start, end;
		std::string first = getBracketContent(duplicate, &start, &end);
		std::string t(skipBracket(duplicate));
		std::string second = getBracketContent(t, &start, &end);
		std::string an;
		an += "an{";
		an += first;
		an += "}{";
		an += second;
		an += '}';
		std::string temp(input->c_str(), an.size(), input->size() - an.size());
		*input = temp;
		return new Context(an);
	} else if (type.compare("ap") == 0 || type.compare("aa") == 0) {
		Proposition* prop = createProposition(duplicate);
		//std::cout << skipBracket(duplicate) << std::endl;
		*input = skipBracket(duplicate);
		return new Context(prop);
	} else {
		//std::cout << "this is duplicate:" << duplicate << std::endl;
		Proposition* prop = createProposition(duplicate);
		*input = skipBracket(skipBracket(duplicate));
		//std::cout << "this is remaining:" << *input << std::endl;
		return new Context(prop);
	}
}

Context::~Context() {
	// TODO Auto-generated destructor stub
}

bool Context::isAnnotated() {
	return (this->mAgentList.size() > 0 || this->mActionList.size() > 0);
}

std::string Context::toLatex() {
	std::string annotation;
	std::string item;
	if (mAgentList.size() > 0) {
		for (size_t i = 0; i < mAgentList.size() - 1; i++) {
			annotation += mAgentList[i]->toLatex();
			annotation += ",";
		}
		annotation += mAgentList.back()->toLatex();
	}
	if (mActionList.size() > 0) {
		for (size_t i = 0; i < mActionList.size() - 1; i++) {
			annotation += mActionList[i]->toLatex();
			annotation += ",";
		}
		annotation += mActionList.back()->toLatex();
	}
	if (this->mType == CONTEXT_PROPOSITION || mType == CONTEXT_ACTION) {
		item += this->mProposition->toLatex();
	} else {
		//std::cout << "Item no:" << mItemList.size() << std::endl;
		for (size_t j = 0; j < mItemList.size() - 1; j++) {
			item += mItemList[j]->toLatex();
			item += ",";
		}
		item += mItemList.back()->toLatex();
	}
	if (!(annotation.size() <= 0
			|| (mItemList.size() == 1
					&& mItemList.front()->getType() == CONTEXT_ACTION
					&& mItemList.front()->getProposition()->getPropName()
							== ACTION)
			|| (mItemList.size() == 1
					&& mItemList.front()->getType() == CONTEXT_PROPOSITION
					&& mItemList.front()->getProposition()->getPropName()
							== ATOMIC))) {
		std::string str("(");
		str += item;
		str += ")";
		item = str;
	}
	std::string result(item);
	if (isAnnotated()) {
		result += "^{";
		result += annotation;
		result += "}";
	}
	return result;
}

bool Context::compare(Context* context) {
	if (mType != context->getType()) {
		return false;
	}

	if (mType == CONTEXT_ACTION || mType == CONTEXT_PROPOSITION) {
		return mProposition->compare(context->getProposition());
	}

	if (mType == PROPOSITIONCONTEXT) {
		if (mAgentList.size() != context->getAgentList().size()
				|| mItemList.size() != context->getItemList().size()) {
			return false;
		} else {
			for (size_t i = 0; i < mAgentList.size(); i++) {
				if (!mAgentList[i]->compare(context->getAgentList()[i])) {
					return false;
				}
			}

			for (size_t j = 0; j < mItemList.size(); j++) {
				if (!mItemList[j]->compare(context->getItemList()[j])) {
					return false;
				}
			}

			return true;
		}
	} else {
		if (mActionList.size() != context->getActionList().size()
				|| mItemList.size() != context->getItemList().size()) {
			return false;
		} else {
			for (size_t i = 0; i < mActionList.size(); i++) {
				if (!mActionList[i]->compare(context->getActionList()[i])) {
					return false;
				}
			}

			for (size_t j = 0; j < mItemList.size(); j++) {
				if (!mItemList[j]->compare(context->getItemList()[j])) {
					return false;
				}
			}

			return true;
		}
	}
}
